﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;

namespace SuperBall3D
{
    public static class Physics
    {


        public const float Gravity = (50 * -9.797645f);

        public static readonly Vector3 gVector = new Vector3(0, Gravity, 0);

        private static double time;

        public static double Time
        {
            get { return Physics.time; }
        }

        public static Plane bottomPlane = new Plane(Vector3.Up, 2500f);
        public const float deltaT = 1 / 60f;

        public const float deltaTSq = deltaT * deltaT;

        public const float deltaTInverse = 1 / deltaT;

        private static int tickCount;

        public static long TickCount
        {
            get { return Physics.tickCount; }
        }

        public static int SecondsToTicks(float seconds)
        {
            return (int)(seconds / deltaT);
        }


        public static void Update(SuperBallGame g)
        {
            tickCount++;
            time += deltaT;
            List<SuperBallObject> toBeRemoved = new List<SuperBallObject>();
            Dictionary<SuperBallObject, List<SuperBallObject>> alreadyCollided = new Dictionary<SuperBallObject, List<SuperBallObject>>();
            foreach (SuperBallObject obj1 in SuperBallObject.DynamicSuperBallObjects)
            {
                foreach (SuperBallObject obj2 in SuperBallObject.AllSuperBallObjects)
                {
                    if (obj1 == obj2)
                        continue;
                    Geometry g1 = obj1.Geo;
                    Geometry g2 = obj2.Geo;

                    Vector3 contactNormal = Vector3.Zero;
                    float penetrationDepth = 0;

                    if ((!alreadyCollided.ContainsKey(obj1) || !(alreadyCollided[obj1].Contains(obj2))) && g1.checkCollision(g2, ref contactNormal, ref penetrationDepth))
                    {

                        Vector3 obj1OldVel = (obj1 as DynamicSuperBallObject).Velocity;
                        Vector3 obj2OldVel = Vector3.Zero;
                        if (obj2 is DynamicSuperBallObject)
                        {
                            obj2OldVel = (obj2 as DynamicSuperBallObject).Velocity;
                            obj1.HandleCollisionWithDynamic(obj2 as DynamicSuperBallObject, obj1OldVel, obj2OldVel, -contactNormal, penetrationDepth);
                        }
                        else
                            obj1.HandleCollisionWithStatic(-contactNormal, penetrationDepth, obj2.FrictionCoefficient);

                        if (obj1 is Player && obj2 is Platform)
                        {
                            toBeRemoved.Add(obj2);
                        }

                        if (alreadyCollided.ContainsKey(obj2))
                            alreadyCollided[obj2].Add(obj1);
                        else
                            alreadyCollided.Add(obj2, new List<SuperBallObject>() { obj1 });

                    }
                }
                switch (obj1.Geo.GeomType)
                {
                    case (Geometry.GeometryType.Box):
                        if (bottomPlane.Intersects(obj1.Geo.BBox) != PlaneIntersectionType.Front)
                        {
                            toBeRemoved.Add(obj1);
                        }
                        break;
                    case(Geometry.GeometryType.Sphere):
                        if (bottomPlane.Intersects(obj1.Geo.BSphere) != PlaneIntersectionType.Front)
                        {
                            toBeRemoved.Add(obj1);   
                        }
                        break;
                    default:
                        throw new Exception("Unsupported geometry type");
                }


            }

            foreach (SuperBallObject obj in toBeRemoved)
            {
                SuperBallObject.RemoveFromGameLists(obj);
                if (obj is Player)
                {
                    g.PlayLosingSound();
                    g.GameOver = true;
                    Thread.Sleep(3000);
                    g.Restart(false);
                }
                else if (obj is Platform)
                {
                    var c = obj as Platform;
                    SuperBallObject.platformList.Remove(c);
                    g.Components.Remove(obj);
                    g.PlayPointSound();
                    /*
                    Thread.Sleep(3000);
                    g.Restart(true);
                    */
                }
                else
                    g.Components.Remove(obj);
            }

        }

    }
}
